import util
import deterSearchAlg
import copy
import time

class PlanningAlg:
    def __init__(self, level, det, heuristic, depth, timeOut):
            self.searchType = det
            self.heuristic = heuristic #initializes A* with something
            self.depthLimit = depth
            self.level = level
            self.timeOut = timeOut
            
    def runAlg(self):
        if(self.heuristic == "ord-lm"): 
            return self.runDisjunctiveSearchControl()
        elif(self.searchType == 'ID'): 
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).iterativeDeeping()
        elif (self.searchType == 'DFS'):
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).depthFirstSearch(self.depthLimit)
        elif (self.searchType == 'BFS'): 
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).breadthFirstSearch()
        elif (self.searchType == 'AS'): 
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).aStar()
        elif (self.searchType == 'BEST'): 
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).bestFirstSearch()   
        elif (self.searchType == 'FF'): 
            time, plan = deterSearchAlg.DeterminSearch(self.level, self.heuristic, self.depthLimit, self.timeOut).fastForwardSearch()    
        return time, plan 
    
    def runDisjunctiveSearchControl(self):
        time1 = 0
        plan = []
        landMarkGraph, landMarkLeaves = self.level.getHOrderLM(self.level)
        subGoalState = self.level
        while (len(landMarkLeaves) != 0):
            disjGoals = landMarkLeaves 
            subTime, subPlan, subGoalState = deterSearchAlg.DeterminSearch(
                                                                           subGoalState, self.heuristic, 
                                                                           self.depthLimit, self.timeOut-time1).disjGoalIterativeDeeping(disjGoals)
            #print subPlan, len(subPlan)-1
            """If an initial goal is in the landmarks then the subplan may be
            empth the check len(subPlan) != 0 accounts for that """
            if len(subPlan) != 0:
                if subPlan[len(subPlan)-1] == "FAIL": 
                    return time1 + subTime, ["FAIL"]
            if time1+subTime > self.timeOut:
                return time1 + subTime, ["FAIL"]
            # print "subGoalState!"
            #print subGoalState
            # time.sleep(3)
            #===================================================================
            # print subPlan
            #===================================================================
            plan = plan + subPlan
            time1 = time1 + subTime
            #===================================================================
            # print time1
            #===================================================================
            if subGoalState.isGoal(): 
                return time1, plan
            landMarkLeaves = self.getNewLeaves(
                                               landMarkGraph, 
                                               landMarkLeaves, subGoalState)
        if subGoalState.isGoal(): 
            return time1, plan
        else: 
            """This runs the last substate in case the while terminated before the
            goal was reached.  Note this a slight modification of DSG 
            where hoffman et al. have a fail safe  """
            return deterSearchAlg.DeterminSearch(subGoalState, self.heuristic, self.depthLimit, self.timeOut).iterativeDeeping()
        
    def getNewLeaves(self, landMarkGraph, landMarkLeaves, state):  
        """
        Builds new leave set for disjointed goal algorithm
        """
        revLandMarkLeaves = copy.deepcopy(landMarkLeaves)
        for leaf in landMarkLeaves:
            if (leaf[1], leaf[0]) not in state.goops.iteritems(): continue
            for neig in landMarkGraph.node_neighbors[leaf]:
                if landMarkGraph.edge_label((leaf, neig)) == 'parent_ptr':
                    parent = neig
                    revLandMarkLeaves.add(parent)
            'Remove old leaf'
            revLandMarkLeaves.remove(leaf)
        return revLandMarkLeaves